package com.mytool.service;

import com.mytool.domain.TableDomain;
import com.mytool.model.GenerateCodeReq;
import com.mytool.util.TemplateEngineService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
@Slf4j
public class GenerateCodeService {

    @Autowired
    private TemplateEngineService templateEngine;

    public byte[] zipContent(GenerateCodeReq req) {
        TableDomain tableMetaData = GenerateCodeHelper.parseDdl(req.getDdlSql());
        Map<String, Object> dataModel = GenerateCodeHelper.prepareDataModel(req, tableMetaData);
        List<File> templates = templates(req);
        Map<String, String> fileContentMap = new HashMap<>();
        try {
            for(File template : templates) {
                String fileContent = templateEngine.processTemplate(req.getFrameworkType() + "-templates/" + template.getName(), dataModel);
                String filepath = GenerateCodeHelper.outFilepath(dataModel, template.getName(), fileContent);
                fileContentMap.put(filepath, fileContent);
            }
        } catch (Exception e) {
            log.error("template engine error:", e);
        }
        return downloadCode(fileContentMap);
    }

    private byte[] downloadCode(Map<String,String> fileContentMap) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zip = new ZipOutputStream(outputStream);
        fileContentMap.forEach((k, v) -> {
            zipContent(zip, k, v);
        });
        try {
            zip.close();
        } catch (Exception e) {
            log.error("zip close error:", e);
        }
        return outputStream.toByteArray();
    }

    private void zipContent(ZipOutputStream zip, String filepath, String fileContent) {
        try{
            zip.putNextEntry(new ZipEntry(filepath));
            StreamUtils.copy(fileContent, StandardCharsets.UTF_8, zip);
            zip.flush();
            zip.closeEntry();
        } catch (Exception e) {
            log.error("zip error:", e);
        }
    }

    private List<File> templates(GenerateCodeReq req) {
        List<File> templates = new ArrayList<>();
        String arch = req.getFrameworkType();
        ClassPathResource pathResource = new ClassPathResource("templates/" + arch + "-templates/");
        try {
            File dir = pathResource.getFile();
            if(dir.isDirectory()) {
                File[] files = dir.listFiles();
                for(File file : files) {
                    templates.add(file);
                }
            }
        } catch (IOException e) {
            log.error("get templates error:", e);
        }
        return templates;
    }
}
